import tkinter as tk
from tkinter import messagebox, scrolledtext
import threading
import time
import json
import sys, os
from datetime import datetime
from PIL import Image, ImageTk
import cv2
import numpy as np

# 导入你的模块
import DXFServer
import game_path_planner
import dnf_skill_recognition
import keyboard

class ModernDNFBotGUI:
    def __init__(self, root):
        # 保存原始的stdout和stderr，以便后续恢复
        self.original_stdout = sys.stdout
        self.original_stderr = sys.stderr

        self.root = root
        self.root.title("灵枢AI")
        self.root.geometry("620x500")
        self.root.resizable(False, False)
        # 初始化时先隐藏窗口
        self.root.withdraw()
        self.is_GPU = 'GPU' if DXFServer.is_cuda_available() else 'CPU'
        self.device = self.is_GPU
        # 设置主题颜色
        self.colors = {
            'primary': '#2c3e50',
            'secondary': '#3498db',
            'success': '#27ae60',
            'warning': '#f39c12',
            'danger': '#e74c3c',
            'light': '#ecf0f1',
            'dark': '#2c3e50',
            'white': '#ffffff',
            'gray': '#95a5a6',
            'info': '#008000',
        }

        # 状态变量
        self.is_running = False
        self.is_paused = False
        self.hwnd = None
        self.planner = None
        self.thread = None

        self.mini_map_templates = None
        self.mini_map_temp_types = None

        # 暂停时的状态保存
        self.paused_state = {
            'current_room': None,
            'current_step': None,
            'distance_flags': None,
            'map_data': None,
            'boss_position': None
        }

        # 定义常量为实例属性，避免每次调用都创建
        self.VALID_TEMPLATES = frozenset({
            './model/islands.png',
            './model/engine.png',
            './model/forest.png'
        })

        self.TEMPLATE_MAP = {
            './model/islands.png': '群岛',
            './model/engine.png': '引擎',
            './model/forest.png': '森林'
        }

        self.DEFAULT_RESULT = {'name': None, 'position': None}

        # 小地图图片显示
        self.mini_map_img = None
        self.map_image_label = None

        self.win_left = None
        self.win_top = None

        # 模板缓存初始化（仅记录有效模板路径）
        self.valid_templates = set()

        # 配置根窗口
        self.setup_root()

        # 创建界面
        self.create_widgets()

        # 执行初始化操作
        self.perform_initialization()

        # 初始化完成后显示窗口
        self.root.deiconify()

        # 窗口关闭时恢复标准输出
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)

    def on_close(self):
        """窗口关闭时恢复标准输出"""
        sys.stdout = self.original_stdout
        sys.stderr = self.original_stderr
        self.root.destroy()

    def perform_initialization(self):
        """在窗口显示前完成所有耗时初始化工作"""
        # 1. 预加载模板（仅检查文件是否存在）
        self.preload_templates()

        # 2. 模板加载完成后，定义小地图模板子集
        self.mini_map_templates = {
            k: v for k, v in self.valid_templates.items()
            if k in ["./model/i.png", "./model/n.png", "./model/b.png"]
        }
        # 3. 模板加载完成后，定义小地图模板子集
        self.mini_map_temp_types = {
            k: v for k, v in self.valid_templates.items()
            if k in ["./model/islands.png", "./model/engine.png", "./model/forest.png"]
        }
        # 4. 短暂延迟确保资源加载完成
        time.sleep(1.5)

    def preload_templates(self):
        template_paths = [
            './model/sly.jpg', './model/brand.png', './model/again.png',
            './model/sy_fb.png', './model/return_town.png', './model/YaoQi_Track.png',
            './model/HongKuAng_Village.png', './model/shop.png', './model/yao_qi_ju_xian_zx.png',
            './model/shan_shan_mi.png', './model/role_tab.png', './model/role_start.png',
            './model/islands.png', './model/engine.png', './model/forest.png', './model/b.png',
            './model/i.png', './model/n.png','./model/close_win.jpg'
        ]

        self.valid_templates = {}
        success_count = 0
        for path in template_paths:
            try:
                if os.path.exists(path):
                    img = cv2.imread(path)  # 直接加载到内存
                    if img is not None:
                        self.valid_templates[path] = img
                        success_count += 1
                    else:
                        self.log_message(f"无法读取模板文件: {path}", "WARNING")
                else:
                    self.log_message(f"模板文件不存在: {path}", "WARNING")
            except Exception as e:
                self.log_message(f"检查模板 {path} 时出错: {str(e)}", "WARNING")

        self.log_message(
            f"模板检查完成：找到 {success_count}/{len(template_paths)} 个有效模板",
            "INFO"
        )

    def setup_root(self):
        """配置根窗口样式"""
        self.root.configure(bg=self.colors['light'])
        self.root.option_add('*TFrame*background', self.colors['light'])
        self.root.option_add('*TLabel*background', self.colors['light'])

    def create_widgets(self):
        """创建界面组件"""
        # 创建主容器
        main_container = tk.Frame(self.root, bg=self.colors['light'])
        main_container.pack(fill=tk.BOTH, expand=True, padx=8, pady=8)

        # 标题区域
        self.create_header(main_container)

        # 主要内容区域
        content_frame = tk.Frame(main_container, bg=self.colors['light'])
        content_frame.pack(fill=tk.BOTH, expand=True, pady=(8, 0))

        # 左侧控制面板
        self.create_control_panel(content_frame)

        # 右侧地图信息面板
        self.create_map_info_panel(content_frame)

        # 底部日志区域
        self.create_log_panel(main_container)

    def create_header(self, parent):
        """创建标题区域"""
        header_frame = tk.Frame(parent, bg=self.colors['primary'], height=45)
        header_frame.pack(fill=tk.X, pady=(0, 8))
        header_frame.pack_propagate(False)

        # 标题
        title_label = tk.Label(
            header_frame,
            text="🎮 DNF自动刷图助手【妖气追踪】",
            font=("Microsoft YaHei UI", 12, "bold"),
            fg=self.colors['white'],
            bg=self.colors['primary']
        )
        title_label.pack(expand=True)

        # 副标题
        subtitle_label = tk.Label(
            header_frame,
            text="智能自动化刷图工具",
            font=("Microsoft YaHei UI", 8),
            fg=self.colors['light'],
            bg=self.colors['primary']
        )
        subtitle_label.pack()

    def create_control_panel(self, parent):
        """创建左侧控制面板"""
        control_frame = tk.Frame(parent, bg=self.colors['white'], relief=tk.RAISED, bd=1)
        control_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=False, padx=(0, 4))
        control_frame.configure(width=180)
        control_frame.pack_propagate(False)

        # 控制面板标题
        control_title = tk.Label(
            control_frame,
            text="⚙️ 控制面板",
            font=("Microsoft YaHei UI", 10, "bold"),
            fg=self.colors['primary'],
            bg=self.colors['white']
        )
        control_title.pack(pady=(8, 4))

        # 游戏窗口检测区域
        self.create_game_detection_section(control_frame)

        # 控制按钮区域
        self.create_control_buttons(control_frame)

    def create_map_info_panel(self, parent):
        """创建右侧地图信息面板"""
        map_frame = tk.Frame(parent, bg=self.colors['white'], relief=tk.RAISED, bd=1)
        map_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(4, 0))

        # 地图信息面板标题
        map_title = tk.Label(
            map_frame,
            text="⚙️ 参数设置",
            font=("Microsoft YaHei UI", 10, "bold"),
            fg=self.colors['primary'],
            bg=self.colors['white']
        )
        map_title.pack(pady=(8, 4))

        # 参数设置区域
        self.create_parameters_section(map_frame)

        # 小地图显示
        self.create_minimap_display_section(map_frame)

    def create_parameters_section(self, parent):
        """创建参数设置区域 - 横向排列"""
        params_frame = tk.LabelFrame(
            parent,
            text="🎯 游戏参数",
            font=("Microsoft YaHei UI", 8, "bold"),
            fg=self.colors['primary'],
            bg=self.colors['white'],
            relief=tk.GROOVE,
            bd=1
        )
        params_frame.pack(fill=tk.X, padx=8, pady=4)

        # 第一行参数
        row1_frame = tk.Frame(params_frame, bg=self.colors['white'])
        row1_frame.pack(fill=tk.X, padx=8, pady=3)

        # 角色
        tk.Label(
            row1_frame,
            text="角色:",
            font=("Microsoft YaHei UI", 7),
            bg=self.colors['white']
        ).pack(side=tk.LEFT)

        self.interval_var = tk.StringVar(value="1")
        interval_entry = tk.Entry(
            row1_frame,
            textvariable=self.interval_var,
            font=("Microsoft YaHei UI", 7),
            width=6,
            relief=tk.SOLID,
            bd=1,
            state="disabled"
        )
        interval_entry.pack(side=tk.LEFT, padx=(2, 8))

        # 角色数量设置
        tk.Label(
            row1_frame,
            text="限制:",
            font=("Microsoft YaHei UI", 7),
            bg=self.colors['white']
        ).pack(side=tk.LEFT)

        self.char_count_var = tk.StringVar(value="1")
        char_entry = tk.Entry(
            row1_frame,
            textvariable=self.char_count_var,
            font=("Microsoft YaHei UI", 7),
            width=6,
            relief=tk.SOLID,
            bd=1
        )
        char_entry.pack(side=tk.LEFT, padx=(2, 8))

        # 疲劳值设置
        tk.Label(
            row1_frame,
            text="疲劳:",
            font=("Microsoft YaHei UI", 7),
            bg=self.colors['white']
        ).pack(side=tk.LEFT)

        self.pl_var = tk.StringVar(value="自动检测")
        pl_entry = tk.Entry(
            row1_frame,
            textvariable=self.pl_var,
            font=("Microsoft YaHei UI", 7),
            width=8,
            relief=tk.SOLID,
            bd=1,
            state="disabled"
        )
        pl_entry.pack(side=tk.LEFT, padx=(2, 8))

        # 移动速度设置
        tk.Label(
            row1_frame,
            text="速度:",
            font=("Microsoft YaHei UI", 7),
            bg=self.colors['white']
        ).pack(side=tk.LEFT)

        self.speed_var = tk.StringVar(value="自动检测")
        speed_entry = tk.Entry(
            row1_frame,
            textvariable=self.speed_var,
            font=("Microsoft YaHei UI", 7),
            width=8,
            relief=tk.SOLID,
            bd=1,
            state="disabled"
        )
        speed_entry.pack(side=tk.LEFT, padx=(2, 8))

        # 身高设置
        tk.Label(
            row1_frame,
            text="身高:",
            font=("Microsoft YaHei UI", 7),
            bg=self.colors['white']
        ).pack(side=tk.LEFT)

        self.height_var = tk.StringVar(value="自动检测")
        height_entry = tk.Entry(
            row1_frame,
            textvariable=self.height_var,
            font=("Microsoft YaHei UI", 7),
            width=8,
            relief=tk.SOLID,
            bd=1,
            state="disabled"
        )
        height_entry.pack(side=tk.LEFT, padx=(2, 8))

        tk.Label(
            row1_frame,
            text="秒",
            font=("Microsoft YaHei UI", 6),
            fg=self.colors['gray'],
            bg=self.colors['white']
        ).pack(side=tk.LEFT)

        # 第二行参数
        row2_frame = tk.Frame(params_frame, bg=self.colors['white'])
        row2_frame.pack(fill=tk.X, padx=8, pady=3)

        # 说明文字
        note_frame = tk.Frame(params_frame, bg=self.colors['white'])
        note_frame.pack(fill=tk.X, padx=8, pady=2)

        tk.Label(
            note_frame,
            text="角色、限制、疲劳、速度、身高",
            font=("Microsoft YaHei UI", 8),
            fg=self.colors['gray'],
            bg=self.colors['white']
        ).pack(side=tk.LEFT)

    def create_minimap_display_section(self, parent):
        """创建小地图显示区域"""
        minimap_frame = tk.LabelFrame(
            parent,
            text="🖼️ 小地图显示",
            font=("Microsoft YaHei UI", 8, "bold"),
            fg=self.colors['primary'],
            bg=self.colors['white'],
            relief=tk.GROOVE,
            bd=1
        )
        minimap_frame.pack(fill=tk.BOTH, expand=True, padx=8, pady=4)

        # 小地图图片显示
        self.map_image_label = tk.Label(
            minimap_frame,
            text="等待小地图数据...",
            font=("Microsoft YaHei UI", 7),
            fg=self.colors['gray'],
            bg=self.colors['light'],
            relief=tk.SUNKEN,
            bd=1
        )
        self.map_image_label.pack(fill=tk.BOTH, expand=True, padx=8, pady=8)

    def update_map_info(self, mini_map_img):
        """更新小地图图片显示"""
        if mini_map_img is not None:
            self.update_minimap_image(mini_map_img)

    def update_minimap_image(self, img_array):
        """更新小地图图片显示"""
        try:
            # 将OpenCV的BGR格式转换为RGB
            if len(img_array.shape) == 3:
                img_rgb = cv2.cvtColor(img_array, cv2.COLOR_BGR2RGB)
            else:
                img_rgb = img_array

            # 调整图片大小以适应显示区域
            height, width = img_rgb.shape[:2]
            max_size = 150

            if width > max_size or height > max_size:
                scale = min(max_size / width, max_size / height)
                new_width = int(width * scale)
                new_height = int(height * scale)
                img_rgb = cv2.resize(img_rgb, (new_width, new_height))

            # 转换为PIL图像
            pil_image = Image.fromarray(img_rgb)

            # 转换为PhotoImage
            photo = ImageTk.PhotoImage(pil_image)

            # 更新标签
            self.map_image_label.config(image=photo, text="")
            self.map_image_label.image = photo  # 保持引用

        except Exception as e:
            self.log_message(f"更新小地图图片失败: {str(e)}", "ERROR")
            self.map_image_label.config(text="图片显示失败", image="")

    def create_game_detection_section(self, parent):
        """创建游戏检测区域"""
        detection_frame = tk.LabelFrame(
            parent,
            text="🎯 游戏窗口检测",
            font=("Microsoft YaHei UI", 8, "bold"),
            fg=self.colors['primary'],
            bg=self.colors['white'],
            relief=tk.GROOVE,
            bd=1
        )
        detection_frame.pack(fill=tk.X, padx=8, pady=4)

        # 状态显示
        status_frame = tk.Frame(detection_frame, bg=self.colors['white'])
        status_frame.pack(fill=tk.X, padx=8, pady=4)

        tk.Label(
            status_frame,
            text="显卡:",
            font=("Microsoft YaHei UI", 7),
            bg=self.colors['white']
        ).pack(side=tk.LEFT)

        self.window_cuda_label = tk.Label(
            status_frame,
            text=self.device,
            font=("Microsoft YaHei UI", 7, "bold"),
            fg=self.colors['success'],
            bg=self.colors['white']
        )
        self.window_cuda_label.pack(side=tk.LEFT, padx=(3, 0))

        tk.Label(
            status_frame,
            text="状态:",
            font=("Microsoft YaHei UI", 7),
            bg=self.colors['white']
        ).pack(side=tk.LEFT)

        self.window_status_label = tk.Label(
            status_frame,
            text="未检测到",
            font=("Microsoft YaHei UI", 7, "bold"),
            fg=self.colors['danger'],
            bg=self.colors['white']
        )
        self.window_status_label.pack(side=tk.LEFT, padx=(3, 0))

        # 检测按钮
        self.detect_btn = tk.Button(
            detection_frame,
            text="🔍 检测游戏窗口",
            command=self.detect_game_window,
            font=("Microsoft YaHei UI", 7, "bold"),
            bg=self.colors['secondary'],
            fg=self.colors['white'],
            relief=tk.FLAT,
            padx=12,
            pady=4,
            cursor="hand2"
        )
        self.detect_btn.pack(pady=(0, 4))

    def create_control_buttons(self, parent):
        """创建控制按钮区域"""
        button_frame = tk.LabelFrame(
            parent,
            text="🎮 操作控制",
            font=("Microsoft YaHei UI", 8, "bold"),
            fg=self.colors['primary'],
            bg=self.colors['white'],
            relief=tk.GROOVE,
            bd=1
        )
        button_frame.pack(fill=tk.X, padx=8, pady=4)

        # 按钮容器
        btn_container = tk.Frame(button_frame, bg=self.colors['white'])
        btn_container.pack(padx=8, pady=6)

        # 开始按钮
        self.start_btn = tk.Button(
            btn_container,
            text="▶️ 开始自动刷图",
            command=self.start_bot,
            font=("Microsoft YaHei UI", 8, "bold"),
            bg=self.colors['success'],
            fg=self.colors['white'],
            relief=tk.FLAT,
            padx=16,
            pady=5,
            cursor="hand2",
            state="disabled"
        )
        self.start_btn.pack(fill=tk.X, pady=(0, 4))

        # 暂停/继续按钮
        self.pause_btn = tk.Button(
            btn_container,
            text="⏸️ 暂停",
            command=self.pause_resume_bot,
            font=("Microsoft YaHei UI", 8, "bold"),
            bg=self.colors['warning'],
            fg=self.colors['white'],
            relief=tk.FLAT,
            padx=16,
            pady=5,
            cursor="hand2",
            state="disabled"
        )
        self.pause_btn.pack(fill=tk.X, pady=(0, 4))

    def create_log_panel(self, parent):
        """创建底部日志区域"""
        log_frame = tk.LabelFrame(
            parent,
            text="📝 运行日志",
            font=("Microsoft YaHei UI", 8, "bold"),
            fg=self.colors['primary'],
            bg=self.colors['white'],
            relief=tk.GROOVE,
            bd=1
        )
        log_frame.pack(fill=tk.BOTH, expand=True, pady=(8, 0))

        # 日志文本框
        self.log_text = scrolledtext.ScrolledText(
            log_frame,
            height=6,
            font=("Consolas", 9),
            bg=self.colors['light'],
            fg=self.colors['dark'],
            relief=tk.SUNKEN,
            bd=1
        )
        self.log_text.pack(fill=tk.BOTH, expand=True, padx=8, pady=8)

    def log_message(self, message, level="INFO"):
        """添加日志消息"""
        timestamp = datetime.now().strftime("%H:%M:%S")

        # 根据级别设置颜色
        colors = {
            "INFO": self.colors['info'],
            "SUCCESS": self.colors['success'],
            "WARNING": self.colors['warning'],
            "ERROR": self.colors['danger']
        }

        log_entry = f"[{timestamp}] {level}: {message}\n"

        self.log_text.insert(tk.END, log_entry)
        self.log_text.tag_add(level, f"end-{len(log_entry)}c", "end-1c")
        self.log_text.tag_config(level, foreground=colors.get(level, self.colors['dark']))

        # 让文本组件自动滚动到最末尾
        self.log_text.see(tk.END)

    def detect_game_window(self):
        """检测游戏窗口并移动到(0, 0)位置"""
        try:
            self.log_message("🔍 正在检测游戏窗口...", "INFO")
            if DXFServer.window_capture_win() is not None:
                self.log_message("✓ vnc后台连接成功", "SUCCESS")

                self.window_status_label.config(text="已检测到", fg=self.colors['success'])
                self.start_btn.config(state="normal")
                self.pause_btn.config(state="disabled")

                # 创建规划器实例
                self.planner = game_path_planner.GamePathPlanner()
                # 模板缓存初始化
                self.planner.valid_templates = self.valid_templates
                self.planner.mini_map_templates = self.mini_map_templates
                self.planner.mini_map_temp_types = self.mini_map_temp_types
                # 设置窗口位置为(0, 0)
                self.planner.win_left, self.planner.win_top = 0, 0
                self.win_left, self.win_top = self.planner.win_left, self.planner.win_top
                self.log_message(f"游戏窗口位置: ({self.planner.win_left}, {self.planner.win_top})", "INFO")
            else:
                self.window_status_label.config(text="未检测到", fg=self.colors['danger'])
                self.start_btn.config(state="disabled")
                self.pause_btn.config(state="disabled")
                self.log_message("✗ vnc后台连接失败", "ERROR")
        except Exception as e:
            self.log_message(f"✗ vnc后台连接失败: {str(e)}", "ERROR")

    def check_expiry(self):
        # 设置到期日期
        end_date = datetime(2025, 10, 1)
        now = datetime.now()
        if now > end_date:
            self.log_message(f"❌ 软件使用已到期！到期日期：{end_date.strftime('%Y-%m-%d')}", "ERROR")
            return True
        else:
            days_remaining = (end_date - now).days
            self.log_message(
                f"✅ 软件可正常使用 | 剩余有效期：{days_remaining}天 | 到期日期：{end_date.strftime('%Y-%m-%d')}",
                "INFO"
            )
            return False

    def start_bot(self):
        """开始自动刷图"""
        # 自动激活游戏窗口
        try:
            self.log_message("✓ 已自动激活游戏窗口", "SUCCESS")
            time.sleep(1.5)
        except Exception as e:
            self.log_message(f"激活游戏窗口失败: {str(e)}", "WARNING")

        self.is_running = True
        self.is_paused = False
        self.start_btn.config(state="disabled")
        self.pause_btn.config(state="normal", text="⏸️ 暂停", bg=self.colors['warning'])
        self.detect_btn.config(state="disabled")

        # 在新线程中运行主逻辑
        self.thread = threading.Thread(target=self.run_bot_logic, daemon=True)
        self.thread.start()

    def pause_resume_bot(self):
        # 确保游戏窗口在前台
        self.ensure_game_window_active()
        self.log_message("待开发中...", "warning")
        time.sleep(15)

    def stop_bot(self):
        """停止自动刷图"""
        self.is_running = False
        self.is_paused = False

        # 设置planner的停止标志
        if self.planner:
            self.planner.set_stop_flag(True)

        self.start_btn.config(state="normal")
        self.pause_btn.config(state="disabled")
        self.detect_btn.config(state="normal")
        self.log_message("已停止自动刷图", "WARNING")

    def ensure_game_window_active(self):
        """确保游戏窗口处于前台"""
        try:
            if self.hwnd:
                current_window = DXFServer.win32gui.GetForegroundWindow()
                if current_window != self.hwnd:
                    DXFServer.win32gui.SetForegroundWindow(self.hwnd)
                    time.sleep(0.3)
        except Exception as e:
            pass

    def run_bot_logic(self):
        clos_task = False
        """运行主逻辑"""
        try:
            self.log_message("▶️ 开始自动刷图...", "INFO")

            # 获取设置
            char_count = int(self.char_count_var.get())

            # 清空身高、清空速度
            self.planner.rise, self.planner.speed = None, None

            temp_sy_fb = self.valid_templates.get('./model/sy_fb.png')
            temp_return_town = self.valid_templates.get('./model/return_town.png')
            while self.is_running:
                # 检测NPC赛利亚房间并计算玩家身高
                found, pos, rise = self.detect_npc_and_calculate_rise()
                self.log_message(f"🕵️ 查找NPC赛利亚:{found} 身高：{rise}", "INFO")

                if found and rise:
                    self.log_message("✨（技能激活闪光）")
                    # 初始化技能
                    self.skill_initialization()
                    # 区域选择
                    print("区域选择")
                    self.world_map_move(temp_sy_fb)
                    print("红矿村")
                    # 红矿村
                    self.hongkuang_village_shown()
                    print("副本选择")
                    # 副本选择
                    self.world_fb_move(temp_return_town)

                    time.sleep(2)

                    # 主循环
                    while self.is_running:
                        minimaps, img = DXFServer.get_mini_map(self)
                        i_position = DXFServer.get_current_root_index(minimaps)
                        # 牛头资料
                        b_found, b_position = self.get_found_position(minimaps, 'b.png')
                        print(f"小地图boss位置：{b_position}")
                        # 加载小地图信息
                        box = (670, 56, 123, 54)
                        mini_map_img = img[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
                        map_data_type = self.get_found_info(DXFServer.get_mini_map_type(self,mini_map_img))
                        print(f"地图分类：{map_data_type}")
                        # 更新界面显示地图信息
                        self.update_map_info(mini_map_img)

                        self.log_message(f"地图分类：{map_data_type} ===牛头资料：{b_position}", "INFO")
                        # 防止网络抖动出现异常
                        if b_found and map_data_type.get('name'):
                            # 开始识别玩家移速
                            if not self.planner.speed:
                                self.infer_moving_speed()
                                # 更新界面显示速度
                                if self.planner.speed:
                                    self.speed_var.set(f"{self.planner.speed:.1f}")
                                if not clos_task:
                                    # 关闭任务提示栏
                                    self.mouse_to_click(785, 202)
                                    clos_task = True
                                    DXFServer.vnc.mouse_move(1000, 100)

                            # 设置BOSS位置和地图数据
                            self.planner.set_i_position(i_position)
                            self.planner.set_boss_position(b_position)
                            self.planner.set_map_data(map_data_type)

                            # 设置日志函数
                            self.planner.set_log_function(self.log_message)

                            path = self.planner.plan_path()
                            self.log_message(f"🔚 规划路径: {path}", "INFO")

                            # 疲劳值剩余
                            pl = self.residue_pl()
                            self.pl_var.set(pl)
                            # 清理显存缓存
                            DXFServer.clear_cuda_cache(False)
                            time.sleep(3)
                            if pl == 0:
                                self.log_message("💯（圆满完成）疲劳已清空、返回城镇", "WARNING")
                                self.select_role_tab(char_count)
                                break
                        time.sleep(2.5)
                time.sleep(4.5)
            self.log_message(f"🎯 目标达成【程序结束】")
        except Exception as e:
            self.log_message(f"🔥爆炸 运行出错: {str(e)}", "ERROR")

    def detect_npc_and_calculate_rise(self, threshold=0.95):
        """检测游戏中的NPC并计算玩家身高"""
        temp_sly = self.valid_templates.get('./model/sly.jpg')
        try:
            data, image = DXFServer.get_win_image_info()
            player_pos = DXFServer.extract_player_pos(data)
            # 查找赛利亚
            # box = (427, 175, 37, 14)  # 更新日期 2025-08-07
            box = (427, 181, 37, 14)
            img = image[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
            stu, _ = DXFServer.template_picture(img, temp_sly, threshold, "sly")
            print(f"赛利亚房间检测：{stu}、玩家位置：{data}、初始化玩家升高：{self.planner.rise}")
            if stu and player_pos and not self.planner.rise:
                # rise = abs(player_pos[1] - 434) 更新日期 2025-08-07
                rise = abs(player_pos[1] - 440)
                self.planner.rise = rise
                self.height_var.set(str(rise))

            return stu, player_pos, self.planner.rise
        except Exception as e:
            self.log_message(f"🚫 检测NPC时出错: {str(e)}", "ERROR")
            return False, None, 0

    def skill_initialization(self):
        """初始化技能"""
        try:
            _, image = DXFServer.get_win_image_info()
            box = (299, 532, 186, 62)
            img = image[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
            dnf_skill_recognition.extract_skill_slots(img)
            self.log_message("✅ 技能初始化完成", "SUCCESS")
        except Exception as e:
            self.log_message(f"🚫 技能初始化出错: {str(e)}", "ERROR")

    def world_map_move(self, temp_sy_fb):
        """世界地图移动"""
        try:
            DXFServer.vnc.key_down(keyboard.Right)
            while True:
                minimaps, img = DXFServer.get_mini_map(self)
                box = (0, 0, 160, 567)
                img = img[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
                stu, pos = DXFServer.template_picture(img, temp_sy_fb, 0.85, "sy_fb")
                print(f"收藏推荐：{stu}:{pos}")
                if stu:
                    self.log_message("✨ 世界地图移动")
                    DXFServer.vnc.key_up(keyboard.Right)
                    time.sleep(0.6)
                    self.mouse_to_click(pos[0], pos[1])
                    time.sleep(1.5)
                    DXFServer.vnc.key_press(keyboard.Space)
                    break
                else:
                    DXFServer.vnc.key_press(keyboard.Tab)
                time.sleep(1.3)
        finally:
            DXFServer.vnc.key_up(keyboard.Right)

    def world_fb_move(self, temp_return_town):
        """移动到副本 - 修复了'image'未定义错误"""
        try:
            DXFServer.vnc.key_down(keyboard.Left)
            temp_YaoQi_Track = self.valid_templates.get('./model/YaoQi_Track.png')
            while self.is_running:
                # 获取图像数据（修复点：定义image变量）
                minimaps, image = DXFServer.get_mini_map(self)
                box = (701, 542, 95, 22)
                img = image[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
                stu, _ = DXFServer.template_picture(img, temp_return_town, 0.75, "temp_return_town")
                if stu:
                    time.sleep(1.5)
                    DXFServer.vnc.key_up(keyboard.Left)
                    box = (0, 286, 267, 41)
                    img = image[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
                    stu, _pos = DXFServer.template_picture(img, temp_YaoQi_Track, 0.75, "temp_YaoQi_Track")
                    print(f"识别副本进入：{stu}==={_pos}")
                    self.mouse_to_click(210, 109)
                    time.sleep(0.9)
                    DXFServer.vnc.key_press(keyboard.Space)
                    self.log_message("✨ 进入副本结束")
                    time.sleep(3)
                    break
                time.sleep(0.3)
        finally:
            DXFServer.vnc.key_up(keyboard.Left)

    def hongkuang_village_shown(self):
        """红矿村显示"""
        temp_HongKuAng_Village = self.valid_templates.get('./model/HongKuAng_Village.png')
        while self.is_running:
            _, image = DXFServer.get_mini_map(self)
            box = (615, 28, 58, 16)
            img = image[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
            stu, _ = DXFServer.template_picture(img, temp_HongKuAng_Village, 0.75, "temp_HongKuAng_Village")
            if stu:
                self.log_message("✨ 红矿村显示")
                DXFServer.vnc.key_down(keyboard.Right)
                time.sleep(0.3)
                DXFServer.vnc.key_up(keyboard.Right)
                break
            time.sleep(0.3)

    def brand_shown(self):
        """翻牌显示"""
        temp_brand = self.valid_templates.get('./model/brand.png')
        while self.is_running:
            data, image = DXFServer.get_win_image_info()
            box = (315, 23, 74, 16)
            img = image[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
            stu, _ = DXFServer.template_picture(img, temp_brand, 0.75, "temp_brand")
            if stu:
                time.sleep(1)
                self.log_message("✅ 翻牌通过", "SUCCESS")
                DXFServer.vnc.key_press(keyboard.Esc)
                break
            time.sleep(1.5)

    def hero_shop(self):
        """英雄商店"""
        temp_shop = self.valid_templates.get('./model/shop.png')
        temp_yao_qi_ju_xian_zx = self.valid_templates.get('./model/yao_qi_ju_xian_zx.png')
        temp_shan_shan_mi = self.valid_templates.get('./model/shan_shan_mi.png')
        while self.is_running:
            data, image = DXFServer.get_win_image_info()
            box = (159, 395, 65, 18)
            img = image[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
            stu, _ = DXFServer.template_picture(img, temp_shop, 0.75, "temp_shop")
            if stu:
                self.log_message("✅ 【神秘商店】", "INFO")
                box = (12, 449, 58, 28)
                img = image[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
                stu_yao_ju, pos_yao_ju = DXFServer.template_picture(img, temp_yao_qi_ju_xian_zx, 0.75, "temp_yao_qi_ju_xian_zx")
                stu_shan_shan, pos_shan_shan = DXFServer.template_picture(img, temp_shan_shan_mi, 0.75, "temp_shan_shan_mi")

                if stu_yao_ju:
                    use_pos = pos_yao_ju
                elif stu_shan_shan:
                    use_pos = pos_shan_shan
                else:
                    use_pos = None
                if use_pos:
                    DXFServer.mouse_to_click(self.planner.win_left, self.planner.win_top, use_pos[0]+12,
                                             use_pos[1]+449)
                    time.sleep(0.5)
                    DXFServer.vnc.key_press(keyboard.Space)
                else:
                    self.log_message('🎯 购买完成！鼠标归位。', "SUCCESS")
                    DXFServer.vnc.key_press(keyboard.Esc)
                    DXFServer.vnc.mouse_move(1000, 100)
                    break
            else:
                break
            time.sleep(1)

    def residue_pl(self):
        """检测疲劳值"""
        try:
            data, image = DXFServer.get_win_image_info()
            box = (705, 590, 35, 8)
            img = image[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
            pl = DXFServer.find_pl(img)
            self.log_message(f"🔋 玩家当前角色PL剩余：{pl} 点", "INFO")
            return pl
        except Exception as e:
            self.log_message(f"检测疲劳值出错: {str(e)}", "ERROR")
            return 0

    def select_role_tab(self, char_count):
        """选择角色标签"""
        DXFServer.vnc.key_press(keyboard.F12)
        temp_HongKuAng_Village = self.valid_templates.get('./model/HongKuAng_Village.png')
        temp_role_tab = self.valid_templates.get('./model/role_tab.png')
        temp_role_start = self.valid_templates.get('./model/role_start.png')
        while True:
            data, image = DXFServer.get_win_image_info()
            # 是否回到城镇外围
            box = (615, 28, 58, 16)
            img = image[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
            stu, _ = DXFServer.template_picture(img, temp_HongKuAng_Village, 0.75, "temp_HongKuAng_Village")
            if stu:
                self.log_message(f"已经回到城镇外围")
                time.sleep(1.2)
                game_path_planner.link_jl()
                time.sleep(3.6)
                DXFServer.vnc.key_press(keyboard.Esc)
                break
            else:
                self.log_message(f"等待2.5s...")
                time.sleep(2.5)
        while True:
            data, image = DXFServer.get_win_image_info()
            box = (348, 518, 46, 12)
            img = image[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
            stu, _ = DXFServer.template_picture(img, temp_role_tab, 0.75, "temp_role_tab")
            if stu:
                self.log_message(f"菜单界面已浮现【准备操作选择角色】")
                time.sleep(1)
                self.mouse_to_click(371, 518)
                time.sleep(1.5)
                # 这个鼠标移动有时候会失效：移动后需要再次校验。
                while True:
                    data, image = DXFServer.get_win_image_info()
                    box = (372, 555, 68, 16)
                    img = image[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
                    stu, _ = DXFServer.template_picture(img, temp_role_start, 0.75, "temp_role_start")
                    if stu:
                        time.sleep(1.6)
                        self.log_message(f"再次挑战已浮现【鼠标移动成功！】")
                        DXFServer.vnc.key_press(keyboard.Right)
                        time.sleep(1.5)
                        DXFServer.vnc.key_press(keyboard.Space)
                        break
                    print(f"等待....【游戏开始】")
                    time.sleep(1.5)
                self.look_SLY_stu()
                time.sleep(1.5)
                interval = float(self.interval_var.get())+1
                self.interval_var.set(str(interval))
                self.log_message(f"✔️ 已完成第 {interval} 个角色", "INFO")
                if interval > char_count:
                    self.log_message(f"🎯 已完成所有 {char_count} 个角色的刷图任务", "SUCCESS")
                    self.is_running = False
                else:
                    self.log_message("↩️ 继续执行下一个刷图任务", "INFO")
                    self.planner.rise = None
                    self.planner.speed = None
                break
            else:
                self.log_message(f"选择角色标识丢失执行【esc按钮菜单形式】")
                DXFServer.vnc.key_press(keyboard.Esc)
            time.sleep(2.5)

    def role_start(self):
        """角色开始"""
        temp_role_start = self.valid_templates.get('./model/role_start.png')
        while self.is_running:
            data, image = DXFServer.get_win_image_info()
            box = (372, 555, 68, 16)
            img = image[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
            stu, _ = DXFServer.template_picture(img, temp_role_start, 0.75, "temp_role_start")
            if stu:
                DXFServer.vnc.key_press(keyboard.Right)
                time.sleep(1.5)
                DXFServer.vnc.key_press(keyboard.Space)
                break
            time.sleep(3.5)

    def look_SLY_stu(self):
        """查看赛利亚状态"""
        temp_sly = self.valid_templates.get('./model/sly.jpg')
        while self.is_running:
            _, image = DXFServer.get_win_image_info()
            # 查找赛利亚
            # box = (427, 175, 37, 14)  更新日期 2025-08-07
            box = (427, 181, 37, 14)
            img = image[box[1]:box[1] + box[3], box[0]:box[0] + box[2]]
            stu, _ = DXFServer.template_picture(img, temp_sly, 0.95, "temp_sly")
            if stu:
                break
            time.sleep(1.5)

    def infer_moving_speed(self):
        """推理移动速度"""
        try:
            DXFServer.vnc.key_press(keyboard.M)
            time.sleep(0.6)
            minimaps, img = DXFServer.get_mini_map(self)
            crop_box = (208, 467, 35, 11)
            cropped_img = img[crop_box[1]:crop_box[1] + crop_box[3], crop_box[0]:crop_box[0] + crop_box[2]]
            speed = DXFServer.calculateMovingSpeed(cropped_img)
            self.log_message(f'🏃 冒险家移速:{speed}', "INFO")
            self.planner.speed = float(speed)
            time.sleep(0.3)
            DXFServer.vnc.key_press(keyboard.M)
        except Exception as e:
            self.log_message(f"推理移动速度出错: {str(e)}", "ERROR")

    def mouse_to_click(self, target_x, target_y):
        """鼠标移动点击"""
        x = self.planner.win_left + int(target_x)
        y = self.planner.win_top + int(target_y)
        DXFServer.vnc.mouse_move(x, y)
        DXFServer.vnc.mouse_left_click()

    def get_found_position(self, maps, param):
        """获取找到的位置"""
        return next(
            (
                (item['found'],
                 tuple(pos // 18 for pos in item['position'])
                 if item['position'] else None)
                for item in maps
                if item['template'].endswith(param)
            ),
            (False, None)
        )

    def get_found_info(self, data_list):
        for item in data_list:
            if item.get('found') and item.get('template') in self.VALID_TEMPLATES:
                pos = item.get('position')
                if isinstance(pos, (list, tuple)) and len(pos) >= 2:
                    name = self.TEMPLATE_MAP.get(item['template'])
                    if name:
                        try:
                            return {
                                'name': name,
                                'position': (pos[0] // 18, pos[1] // 18)
                            }
                        except Exception:
                            pass
                break  # 找到符合的模板即停止遍历
        return self.DEFAULT_RESULT

    def get_current_params(self):
        """获取当前参数设置"""
        return {
            'char_count': int(self.char_count_var.get()),
            'interval': float(self.interval_var.get())
        }


def main():
    root = tk.Tk()
    ModernDNFBotGUI(root)
    root.mainloop()


if __name__ == "__main__":
    main()